package com.mybook.app.service;

import com.github.pagehelper.PageInfo;
import com.mybook.app.core.BaseResponse;
import com.mybook.app.core.UserContext;
import com.mybook.app.core.WebPageInfo;
import com.mybook.app.dto.TransAndBookInfoAndUserInfoDto;
import com.mybook.app.dto.TransAndBookInfoDto;
import com.mybook.app.dto.TransAndUserIdDto;
import com.mybook.app.error.Error;
import com.mybook.app.exception.BorrowDataException;
import com.mybook.app.exception.DataIsEmptyException;
import com.mybook.app.exception.WebException;
import com.mybook.app.mapper.BookInfoMapper;
import com.mybook.app.mapper.ProcInfoMapper;
import com.mybook.app.mapper.TransInfoMapper;
import com.mybook.app.model.BookInfo;
import com.mybook.app.model.ProcInfo;
import com.mybook.app.model.TransInfo;
import com.mybook.app.renum.BorrowStatusEnum;
import com.mybook.app.renum.UStatusEnum;
import com.mybook.app.request.BorrowApplyRequest;
import com.mybook.app.request.BorrowCancelRequest;
import com.mybook.app.request.BorrowKeeperDetailRequest;
import com.mybook.app.request.BorrowListRequest;
import com.mybook.app.utils.IdUtils;
import com.mybook.app.utils.LatLngUtils;
import com.mybook.app.utils.Logger;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by zjutsw on 2017/11/10.
 */
@Service
public class BorrowService {

    @Autowired
    private TransInfoMapper transInfoMapper;
    @Autowired
    private BookInfoMapper bookInfoMapper;
    @Autowired
    private ProcInfoMapper procInfoMapper;
    @Autowired
    private WalletService walletService;
    @Autowired
    private UserService userService;


    /**
     * 借阅列表
     *
     * @param borrowListRequest
     * @return
     */
    public BaseResponse list(BorrowListRequest borrowListRequest) {

        borrowListRequest.setUserId(UserContext.getCurrentuserId().get());

        List<TransAndBookInfoDto> transAndBookInfoDtos = transInfoMapper.findTransInfoAndBookInfo(borrowListRequest);

        if (CollectionUtils.isEmpty(transAndBookInfoDtos)) {
            //收藏列表
            Logger.info(this, "查询借阅列表为空");
            throw new DataIsEmptyException();
        }
        // 分页查询信息
        PageInfo<TransAndBookInfoDto> pageInfo = new PageInfo<>(transAndBookInfoDtos);

        WebPageInfo webPageInfo = new WebPageInfo();
        BeanUtils.copyProperties(pageInfo, webPageInfo);
        BaseResponse baseResponse = new BaseResponse(transAndBookInfoDtos, webPageInfo);

        return baseResponse;
    }

    /**
     * 持有者借阅列表
     *
     * @param borrowListRequest
     * @return
     */
    public BaseResponse listKeeper(BorrowListRequest borrowListRequest) {

        borrowListRequest.setUserId(UserContext.getCurrentuserId().get());

        List<TransAndBookInfoDto> transAndBookInfoDtos = transInfoMapper.findTransInfoAndBookInfoAndKeeper(borrowListRequest);

        List<TransAndBookInfoDto> transAndBookInfoDtos2 = new ArrayList<>(transAndBookInfoDtos);

        List<TransAndBookInfoDto> transAndBookInfoDtos3 = new ArrayList<>(transAndBookInfoDtos);

        for(TransAndBookInfoDto transAndBookInfoDto : transAndBookInfoDtos3) {
            if("agreeBorrow".equals(transAndBookInfoDto.getStatus())){
                String name = transAndBookInfoDto.getUrl1();
                for(TransAndBookInfoDto dto : transAndBookInfoDtos2){
                    if(!"agreeBorrow".equals(dto.getStatus()) && name.equals(dto.getUrl1())){
                        transAndBookInfoDtos.remove(dto);
                    }
                }
            }
        }

        if (CollectionUtils.isEmpty(transAndBookInfoDtos)) {
            //收藏列表
            Logger.info(this, "查询借阅列表为空");
            throw new DataIsEmptyException();
        }
        // 分页查询信息
        PageInfo<TransAndBookInfoDto> pageInfo = new PageInfo<>(transAndBookInfoDtos);

        WebPageInfo webPageInfo = new WebPageInfo();
        BeanUtils.copyProperties(pageInfo, webPageInfo);
        BaseResponse baseResponse = new BaseResponse(transAndBookInfoDtos, webPageInfo);

        return baseResponse;
    }

    /**
     * 持有者借阅列表
     *
     * @param borrowListRequest
     * @return
     */
    public TransAndBookInfoAndUserInfoDto listKeeperDetail(BorrowKeeperDetailRequest borrowListRequest) {

        TransAndBookInfoAndUserInfoDto transAndBookInfoDtos = transInfoMapper.findTransInfoByBidAndUserIdAndApply(borrowListRequest.getbId(), UserContext.getCurrentuserId().get());

        if (null == transAndBookInfoDtos) {
            //收藏列表
            Logger.info(this, "查询借阅列表为空");
            throw new DataIsEmptyException();
        }

        String userCoor = userService.getCoor();
        List<TransAndUserIdDto> transAndUserIdDtos = transAndBookInfoDtos.getTransAndUserIdDtos();
        // 不为空，距离计算
        if (CollectionUtils.isNotEmpty(transAndUserIdDtos)) {
            transAndBookInfoDtos.setTransAndUserIdDtos(transAndUserIdDtos.stream().map(transAndBookInfoDto -> {
                String coor = transAndBookInfoDto.getCoor();
                transAndBookInfoDto.setCoor(String.valueOf(LatLngUtils.getDistance(userCoor, coor)));
                return transAndBookInfoDto;
            }).collect(Collectors.toList()));
        }

//        // 分页查询信息
//        PageInfo<TransAndBookInfoAndUserInfoDto> pageInfo = new PageInfo<>(transAndBookInfoDtos);
//
//        WebPageInfo webPageInfo = new WebPageInfo();
//        BeanUtils.copyProperties(pageInfo, webPageInfo);
//        BaseResponse baseResponse = new BaseResponse(transAndBookInfoDtos, webPageInfo);

        return transAndBookInfoDtos;
    }


    /**
     * 借阅人
     * 申请借阅
     *
     * @param
     * @return
     */
    public void apply(BorrowApplyRequest borrowApplyRequest) {
        List<TransInfo> transInfos = transInfoMapper.findTransInfoByBidAndUserId(borrowApplyRequest.getbId(), UserContext.getCurrentuserId().get());

        BookInfo bookInfo = bookInfoMapper.findBookInfoById(borrowApplyRequest.getbId());

        // 不存在的书籍
        if (null == bookInfo) {
            Logger.info(this, "不存在的书籍");
            throw new BorrowDataException(Error.NOT_EXIST_BOOK, borrowApplyRequest.getbId());
        }


        //判断是否已经有借阅信息了
        if (CollectionUtils.isNotEmpty(transInfos)) {
            Logger.info(this, "已经提交借阅请求");
            return;
            //throw new BorrowDataException(Error.EXIST_BORROW_REQUEST, transInfos.get(0).getId());
        }

        if (1 != bookInfo.getBorrowStatus()) {
            // 该书籍不可借阅
            Logger.info(this, "该书籍不可借阅");

            throw new BorrowDataException(Error.NOT_BORROW_BOOK, borrowApplyRequest.getbId());
        }


        // 借阅者表
        String id = IdUtils.getId(userService.getCity());
        // 借阅信息
        saveTransInfo(id, borrowApplyRequest.getbId(), UStatusEnum.borrow, bookInfo, BorrowStatusEnum.apply);
        // 持有
        saveTransInfo(id, borrowApplyRequest.getbId(), UStatusEnum.keeper, bookInfo, BorrowStatusEnum.borrow);
        //记录日志
        recordProcInfo(id, borrowApplyRequest.getbId(), BorrowStatusEnum.apply);
    }

    /**
     * 借阅人
     * 申请后操作
     *
     * @param
     * @return
     */
    @Transactional(rollbackFor = WebException.class)
    public void applyOper(BorrowCancelRequest borrowCancelRequest) {

        TransInfo transInfo = transInfoMapper.findTransInfoBybidAndUStatus(borrowCancelRequest.getId(), UStatusEnum.borrow);
        if (null == transInfo) {
            Logger.info(this, "不存在该借阅");
            throw new BorrowDataException(Error.NOT_EXIST_BORROW_REQUEST, "");
        }

        switch (borrowCancelRequest.getBorrowStatusEnum()) {
            //取消阅读
            case cancelRead: {

                //判断是否可以取消借阅
                if (!BorrowStatusEnum.apply.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "取消借阅");
                }

                // 借阅人，取消借阅
                int row = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelRead, UStatusEnum.borrow);
                Logger.info(this, "取消借阅 ：" + row);

                int row2 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelBorrow, UStatusEnum.keeper);
                Logger.info(this, "取消借阅 ：" + row2);
                break;
            }
            // 接收操作
            case readIng: {

                //判断是否存可以接收操作
                if (!BorrowStatusEnum.agreeApply.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "接收操作");
                }

                //接收操作，设置书籍不可借阅
                int row = bookInfoMapper.updateBookInfoBorrowStatusByBid(2, borrowCancelRequest.getbId());
                Logger.info(this, "修改书籍状态 ：" + row);

                // 借阅人，同意借阅
                int row3 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.readIng, UStatusEnum.borrow, new Date(), null, null, null);
                Logger.info(this, "同意操作 ：" + row3);

                int row4 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.borrowed, UStatusEnum.keeper, new Date(), null, null, null);
                Logger.info(this, "同意操作 ：" + row4);

                //修改书籍持有人
                int row5 = bookInfoMapper.updateBookInfoCuIdByBid(borrowCancelRequest.getbId(), UserContext.getCurrentuserId().get());
                Logger.info(this, "修改持有人 ：" + row5);

                //增加借阅次数
                int row6 = bookInfoMapper.updateBookInfoBorrowsByBid(borrowCancelRequest.getbId());
                Logger.info(this, "增加借阅次数 ：" + row6);

                break;
            }
            // 对方同意后取消
            case cancelApply: {

                //判断是否存可以对方同意取消
                if (!BorrowStatusEnum.agreeApply.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "对方同意后取消");
                }
                // 借阅人，取消借阅
                int row5 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelApply, UStatusEnum.borrow);
                Logger.info(this, "对方同意后取消 ：" + row5);

                int row6 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelBorrowed, UStatusEnum.keeper);
                Logger.info(this, "对方同意后取消 ：" + row6);
                break;
            }
            // 读完操作
            case readed: {

                //判断是否存可以读完操作
                if (!BorrowStatusEnum.readIng.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "读完操作");
                }


                TransInfo transInfo2 = transInfoMapper.findTransInfoByIdAndUStatus(borrowCancelRequest.getId(), UStatusEnum.borrow);
                Integer price = transInfo2.getPrice();
                Date iTime = transInfo2.getiTime();
                Date eTime = new Date();
                // 计算收益
                BigDecimal cost = calCost(iTime, eTime, price);
                BookInfo bookInfo = bookInfoMapper.findBookInfoById(borrowCancelRequest.getbId());
                BigDecimal income = new BigDecimal(1);
                if (null != bookInfo && bookInfo.getOuId().equalsIgnoreCase(transInfo2.getU1Id())) {
                    int row8 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), null, UStatusEnum.keeper, null, new Date(), cost, new BigDecimal(0));
                    Logger.info(this, "读完操作 ：" + row8);
                } else {
                    int row8 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), null, UStatusEnum.keeper, null, new Date(), cost.min(income), income);
                    Logger.info(this, "读完操作 ：" + row8);
                }
                // 查询是否需要归还
                if (1 == transInfo2.getFlag()) {
                    Logger.info(this, "需要收回，归还所有者");
                    TransInfo transInfo3 = new TransInfo();
                    BeanUtils.copyProperties(transInfo2, transInfo3);
                    transInfo3.setU1Id(UserContext.getCurrentuserId().get());
                    transInfo3.setU2Id(bookInfo.getOuId());
                    transInfo3.setType2(UStatusEnum.owner);
                    transInfo3.setStatus(BorrowStatusEnum.readedBack);
                    transInfo3.setuStatus(UStatusEnum.owner);
                    int row = transInfoMapper.insertSelective(transInfo3);
                    Logger.info(this, "插入所属人信息 ：" + row);
                    // 读完操作
                    int row7 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.readedReturn, UStatusEnum.borrow, null, new Date(), null, null);
                    Logger.info(this, "待归还 ：" + row7);

                } else {
                    //读完操作，设置书籍可借阅
                    int row = bookInfoMapper.updateBookInfoBorrowStatusByBid(1, borrowCancelRequest.getbId());
                    Logger.info(this, "修改书籍状态 ：" + row);

                    // 读完操作
                    int row7 = transInfoMapper.updateTransInfoByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.readed, UStatusEnum.borrow, null, new Date(), null, null);
                    Logger.info(this, "读完操作 ：" + row7);


                }

                // 租金支付给书本所有者
                walletService.payWt(cost.min(income), UserContext.getCurrentuserId().get(), bookInfo.getOuId(), bookInfo.getId(), transInfo2.getId());
                // 租金支付给书本持有者
                walletService.payWt(cost.min(income), UserContext.getCurrentuserId().get(), bookInfo.getOuId(), bookInfo.getId(), transInfo2.getId());

                break;
            }
            // 点击收回
            case back: {

                TransInfo transInfo4 = transInfoMapper.findTransInfoBybidAndUStatus(borrowCancelRequest.getId(), UStatusEnum.owner);
                //判断是否存可以读完操作
                if (!BorrowStatusEnum.readedBack.equals(transInfo4.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "点击回收操作");
                }

                // 点击收回
                int row5 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.returned, UStatusEnum.borrow);
                Logger.info(this, "收回操作 ：" + row5);

                int row6 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.back, UStatusEnum.owner);
                Logger.info(this, "收回操作 ：" + row6);

                //接收操作，设置书籍可借阅
                int row = bookInfoMapper.updateBookInfoBorrowStatusByBid(1, borrowCancelRequest.getbId());
                Logger.info(this, "修改书籍状态 ：" + row);

                break;
            }
            default:
                Logger.warn(this, "不存在的状态");
                throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "操作");
        }

        //记录日志
        recordProcInfo(borrowCancelRequest.getId(), borrowCancelRequest.getbId(), borrowCancelRequest.getBorrowStatusEnum());

    }

    /**
     * 持有人
     * 书籍被申请后操作
     *
     * @param
     * @return
     */
    @Transactional(rollbackFor = WebException.class)
    public void oper(BorrowCancelRequest borrowCancelRequest) {
        TransInfo transInfo = transInfoMapper.findTransInfoBybidAndUStatus(borrowCancelRequest.getId(), UStatusEnum.keeper);
        if (null == transInfo) {
            Logger.info(this, "不存在该借阅");
            throw new BorrowDataException(Error.NOT_EXIST_BORROW_REQUEST, "");
        }
        switch (borrowCancelRequest.getBorrowStatusEnum()) {

            case agreeBorrow: {
                //判断是否存可以读完操作
                if (!BorrowStatusEnum.borrow.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "同意借阅");
                }

                // 持有人，同意借阅
                int row = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.agreeBorrow, UStatusEnum.keeper);
                Logger.info(this, "同意借阅 ：" + row);
                int row2 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.agreeApply, UStatusEnum.borrow);
                Logger.info(this, "同意借阅 ：" + row2);

                //拒绝其他人操作
                // 持有人，拒绝借阅
                int row3 = transInfoMapper.updateTransInfoStatusByBIdAndUStatus(borrowCancelRequest.getbId(), BorrowStatusEnum.refuseBorrow, UStatusEnum.keeper,borrowCancelRequest.getId());
                Logger.info(this, "拒绝借阅 ：" + row3);

                int row4 = transInfoMapper.updateTransInfoStatusByBIdAndUStatus(borrowCancelRequest.getbId(), BorrowStatusEnum.refuseApply, UStatusEnum.borrow,borrowCancelRequest.getId());
                Logger.info(this, "拒绝借阅 ：" + row4);
                break;
            }
            case refuseBorrow: {

                //判断是否存可以读完操作
                if (!BorrowStatusEnum.borrow.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "拒绝借阅");
                }

                // 持有人，拒绝借阅
                int row3 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.refuseBorrow, UStatusEnum.keeper);
                Logger.info(this, "拒绝借阅 ：" + row3);

                int row4 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.refuseApply, UStatusEnum.borrow);
                Logger.info(this, "拒绝借阅 ：" + row4);
                break;
            }

            case cancelBorrowed: {

                //判断是否存可以读完操作
                if (!BorrowStatusEnum.agreeBorrow.equals(transInfo.getStatus())) {
                    Logger.info(this, "当前状态：" + transInfo.getStatus());
                    throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "取消借阅");
                }
                // 持有人，取消借出
                int row5 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelBorrowed, UStatusEnum.keeper);
                Logger.info(this, "对方同意后取消 ：" + row5);

                int row6 = transInfoMapper.updateTransInfoStatusByIdAndUStatus(borrowCancelRequest.getId(), BorrowStatusEnum.cancelApply, UStatusEnum.borrow);
                Logger.info(this, "对方同意后取消 ：" + row6);
                break;
            }
            default:
                Logger.warn(this, "不存在的状态");
                throw new BorrowDataException(Error.READ_REQUEST_STATUS_ERROR, "操作");
        }
        //记录日志
        recordProcInfo(borrowCancelRequest.getId(), borrowCancelRequest.getbId(), borrowCancelRequest.getBorrowStatusEnum());
    }


    /**
     * 保存借阅日志
     *
     * @param id
     * @param bId
     */
    public void recordProcInfo(String id, String bId, BorrowStatusEnum borrowStatusEnum) {

        ProcInfo procInfo = new ProcInfo();
        procInfo.setId(id);
        procInfo.setbId(bId);
        procInfo.setStatus(borrowStatusEnum);
        procInfo.setuId(UserContext.getCurrentuserId().get());
        procInfo.setcTime(new Date());
        int row = procInfoMapper.insertSelective(procInfo);
        Logger.info(this, "记录借阅日志 ：" + row);
    }

    /**
     * 计算收益
     *
     * @return (e_time-i_time)<=14,cost=2，(e_time-i_time)>14,（（e_time-i_time）/7-2）*price+2
     */
    private BigDecimal calCost(Date iTime, Date eTime, Integer price) {
        BigDecimal cost = new BigDecimal(0);
        long day = ((eTime.getTime() - iTime.getTime()) / (1000 * 60 * 60 * 24));
        if (day <= 14L) {
            cost = cost.add(new BigDecimal(2));
        } else {
            cost = cost.add(new BigDecimal(((day / 7) - 2) * price + 2));
        }
        return cost;
    }

    /**
     * 保存借阅信息
     *
     * @param id
     * @param bId
     * @param uStatusEnum
     * @param bookInfo
     * @param borrowStatusEnum
     */
    public void saveTransInfo(String id, String bId, UStatusEnum uStatusEnum, BookInfo bookInfo, BorrowStatusEnum borrowStatusEnum) {
        TransInfo transInfo2 = new TransInfo();
        transInfo2.setId(id);
        transInfo2.setbId(bId);
        transInfo2.setcTime(new Date());
        transInfo2.setuTime(new Date());
        transInfo2.setuStatus(uStatusEnum);
        //transInfo.setCost();
        //transInfo.seteTime();
        //transInfo.setiTime();
        //transInfo.setIncome();
        transInfo2.setU2Id(UserContext.getCurrentuserId().get());
        transInfo2.setType2(UStatusEnum.borrow);
        transInfo2.setType1(UStatusEnum.keeper);
        transInfo2.setU1Id(bookInfo.getCuId());
        transInfo2.setStatus(borrowStatusEnum);
        transInfo2.setFlag(bookInfo.getFlag());
        transInfo2.setPrice(bookInfo.getPrice());
        int row = transInfoMapper.insertSelective(transInfo2);
        Logger.info(this, "保存借阅信息 ：" + row);
    }

}
